package com.innovation.ic.b1b.monitor.base.handler;

import com.google.common.base.Strings;
import com.innovation.ic.b1b.monitor.base.mapper.RedisAvailableJobLogMapper;
import com.innovation.ic.b1b.monitor.base.mapper.RedisAvailableJobMapper;
import com.innovation.ic.b1b.monitor.base.mapper.RedisMapper;
import com.innovation.ic.b1b.monitor.base.model.Redis;
import com.innovation.ic.b1b.monitor.base.model.RedisAvailableJob;
import com.innovation.ic.b1b.monitor.base.model.RedisAvailableJobLog;
import com.innovation.ic.b1b.monitor.base.pojo.constant.Constant;
import com.innovation.ic.b1b.monitor.base.pojo.constant.JobDataMapConstant;
import com.innovation.ic.b1b.monitor.base.pojo.enums.ActiveEnum;
import com.innovation.ic.b1b.monitor.base.value.TimeSetConfig;
import lombok.SneakyThrows;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import redis.clients.jedis.Jedis;
import javax.annotation.Resource;
import java.sql.Date;
import java.util.Random;

/**
 * @desc   监控redis可用任务处理类
 * @author linuo
 * @time   2023年3月28日14:59:04
 */
public class RedisAvailableJobHandler extends QuartzJobBean {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Resource
    private RedisAvailableJobLogMapper redisAvailableJobLogMapper;

    @Resource
    private RedisAvailableJobMapper redisAvailableJobMapper;

    @Resource
    private RedisMapper redisMapper;

    @Resource
    private TimeSetConfig timeSetConfig;

    @Resource
    private HandlerHelper handlerHelper;

    @SneakyThrows
    @Override
    protected void executeInternal(org.quartz.JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("开始执行监控rabbitmq可用任务");

        // 获取1-5间的随机数
        int min = 1;
        int max = 5;
        Random random = new Random();
        int s = random.nextInt(max) % (max - min + 1) + min;
        int sleepTime = s * 1000;
        log.info("休眠[{}]秒", s);
        Thread.sleep(sleepTime);

        JobDataMap jobDataMap = jobExecutionContext.getMergedJobDataMap();
        int id = jobDataMap.getInt(JobDataMapConstant.ID);
        RedisAvailableJob redisAvailableJob = redisAvailableJobMapper.selectById(id);
        if(redisAvailableJob != null){
            Redis redis = redisMapper.selectById(redisAvailableJob.getRedisId());
            if(redis != null){
                String redisName = redis.getName();

                // 存活状态
                Integer active = ActiveEnum.NO.getCode();

                RedisAvailableJobLog redisAvailableJobLog = new RedisAvailableJobLog();
                redisAvailableJobLog.setRedisAvailableJobId(id);
                redisAvailableJobLog.setStartTime(new Date(System.currentTimeMillis()));

                if(Strings.isNullOrEmpty(redis.getNodes())){
                    String message = redisName + "配置信息不完整,无法检测是否存活";
                    log.info(message);
                    redisAvailableJobLog.setDescription(message);
                }else{
                    try {
                        StringBuilder sb = new StringBuilder();

                        String nodes = redis.getNodes();
                        nodes = nodes.replaceAll(" ", "");
                        String[] split = nodes.split(",");
                        for(String node : split){
                            String[] split1 = node.split(":");
                            if(split1.length == 2){
                                // 判断redis是否可用
                                String result = judgeRedisIfAvailable(split1[0], Integer.parseInt(split1[1]), redis.getPassword());
                                if(Strings.isNullOrEmpty(result)){
                                    log.info("redis[{}]连接成功", node);
                                }else{
                                    sb.append(node).append(Constant.PAUSE);
                                }
                            }
                        }

                        String message = sb.toString();
                        if(Strings.isNullOrEmpty(message)){
                            active = ActiveEnum.YES.getCode();
                        }else{
                            if(message.endsWith(Constant.PAUSE)){
                                message = message.substring(0, message.length() - 1);
                            }
                            message += "节点连接失败";
                            redisAvailableJobLog.setDescription(message);
                        }
                    }catch (Exception e){
                        log.warn("监控redis是否可用任务出现问题,原因:", e);
                        String message = e.toString();
                        if(!Strings.isNullOrEmpty(message)){
                            if(message.length() > 100){
                                message = message.substring(0, 100);
                            }
                            redisAvailableJobLog.setDescription(message);
                        }
                    }
                }

                redisAvailableJobLog.setActive(active);
                int insert = redisAvailableJobLogMapper.insert(redisAvailableJobLog);
                if(insert > 0){
                    log.info("redis可用任务日志插入成功");

                    if(active.intValue() == ActiveEnum.NO.getCode().intValue()){
                        // 发送邮件
                        String message = redisName + "出现异常，原因：" + redisAvailableJobLog.getDescription() + "，请查看Redis状态并及时进行异常处理。";
                        handlerHelper.sendEmail(redisAvailableJob.getAlarmEmail(), message, null);
                    }
                }
            }else{
                log.info("redis配置信息不存在,无法执行任务");
            }
        }else{
            log.info("监控redis可用任务id=[{}]的数据不存在,无法执行任务", id);
        }
    }

    /**
     * 判断redis是否可用
     * @param host redis地址
     * @param port 端口
     * @return 返回判断结果
     */
    private String judgeRedisIfAvailable(String host, int port, String password) throws InterruptedException {
        String result = null;

        Jedis jedis = new Jedis(host, port);
        try {
            log.info("第一次执行监控redis是否可用任务");
            if(!Strings.isNullOrEmpty(password)){
                jedis.auth(password);
            }
            log.info("输出jedis.ping()结果: " + jedis.ping());
            boolean connected = jedis.isConnected();
            if(connected){
                jedis.close();
            }
        }catch (Exception e){
            log.info("redis连接出现问题,原因:", e);
            log.info("{}秒后进行连接重试", timeSetConfig.getRetryWaitTime());
            Thread.sleep(timeSetConfig.getRetryWaitTime() * 1000);
            try {
                log.info("进行第二次连接重试");
                jedis = new Jedis(host, port);
                if(!Strings.isNullOrEmpty(password)){
                    jedis.auth(password);
                }
                log.info("输出jedis.ping()结果: " + jedis.ping());
                boolean connected = jedis.isConnected();
                if(connected){
                    jedis.close();
                }
            }catch (Exception e1){
                log.info("redis连接出现问题,原因:", e);
                log.info("{}秒后进行连接重试", timeSetConfig.getRetryWaitTime());
                Thread.sleep(timeSetConfig.getRetryWaitTime() * 1000);
                try {
                    log.info("进行第三次连接重试");
                    jedis = new Jedis(host, port);
                    if(!Strings.isNullOrEmpty(password)){
                        jedis.auth(password);
                    }
                    log.info("输出jedis.ping()结果: " + jedis.ping());
                    boolean connected = jedis.isConnected();
                    if(connected){
                        jedis.close();
                    }
                }catch (Exception e2){
                    log.info("redis连接出现问题,原因:", e);
                    result = e.toString();
                }
            }
        }

        return result;
    }
}